package viz_main;

import java.util.HashMap;
import java.util.Vector;

import model.DataHandler;

import buttons.TextButton;

import controllers.C_BarView;
import controllers.C_TreeMap;
import controllers.C_TooltipControl;
import controllers.ControlManager;
import processing.core.*;
import utilities.EventListener;
import utilities.EventOwner;
import view.DisplayList;
import view.V_Applet;
import view.V_Tooltip;
import viz_ui.GridView;
import viz_ui.MappingManager;
import viz_ui.ParallelView;
import viz_ui.BarView;
import viz_ui.TreeMapView;

/*
 * This is the main Processing Applet.
 * Other important objects will contain a reference to this applet so that the PApplet methods
 * Can be used appropriately.
 * 
 * Drawing to the PApplet is done by passing a pointer on display to the given object.
 */
public class VizApplet extends V_Applet implements EventListener{

  private DataHandler database;	
	
  public final float baseS = 5.0f;
  public final float maxS = 12.0f;
  public final float minS = 1.0f;
  public int totalRecords = 0;
  public float gridSize = 400;
  
  // Items:
  private MappingManager globalUIElements;
  public String labels[];
 // private HashMap[] axisList; // store dynamically added axis and axis attributes as hashmaps
  
  private GridView[] charts; 
  private ParallelView parrallelCoordinateView;
  private BarView barChartView;
  private C_BarView barChartControl;
  private TreeMapView treeView;
  private C_TreeMap treeMapControl;
  
  // INTERACTION SETTINGS:
  private int totalWait = 5; // how many frames to wait for a double click before sending a left-click event to model features
  private int clickWait = 0; // the current wait count (ie: "2 of 7")
  public boolean fieldActive = false;
  public boolean dragAvailable = true;
  private TextButton deselectButton;

  // APPEARANCE SETTINGS:
  public final int backgroundColor = color(170, 170, 170);
  public final int selectedColor = color(80, 80, 255);
  public final int panelColor = color(230, 230, 230);
  public final int Color = color(0,0,0);
  public final int boxColor = color(255, 255, 255);
  public final int pointColor = color(0,0,0);
  public final int selectedPointColor = color(20,100,300);
  public final int colors[] = {color(0,0,255), color(0,140,0), color(225,0,0), color(255, 253, 85), color(230, 192, 64)};
  int[] gradientColors = {colors[1], colors[2]};
  int[] generatedGradient;
  // --- Fonts:
  final int bodyFontSize = 12;
  final private PFont body = createFont("Candara-12", bodyFontSize);
  final private PFont header = createFont("Candara-Bold", 16);
  private PFont baseFont = createFont("Arial-Black-12", 14);
  private int pad = 20; // space between gridViews

  public void setup()
  {
    size( 1024, 720 ); // window resizes according to pad
    background( backgroundColor );
    smooth();
    
    viewManager = new DisplayList(true, this);
    controlManager = new ControlManager(this, viewManager);
    // instantiate tooltip feature:
    vTooltip = new V_Tooltip(this);
    cTooltip = new C_TooltipControl(vTooltip, controlManager);
    
    charts = new GridView[1];
    database = new DataHandler();
    database.parseCSV();
    labels = database.getLabels();
    
    //GridView tmpGrid = new GridView(pad+0.0f, pad+10.0f, gridSize, gridSize, controlManager, this);
    //tmpGrid.setXAxis((ScatterPlotAxis)axisList[0].get(labels[0]));
    //tmpGrid.setYAxis((ScatterPlotAxis)axisList[0].get(labels[1]));
    //tmpGrid.generatePoints(totalRecords);
    //tmpGrid.setIndex(0);
    //charts[0] = tmpGrid;

    parrallelCoordinateView = new ParallelView((pad*2)+gridSize, pad+10, 520, 500, this);
    //parrallelCoordinateView.initAxis(axisList[1], null, controlManager);
    
    barChartView = new BarView(gridSize+100+70+(pad*2), pad*2, gridSize, gridSize, controlManager, this);
    barChartView.setXAxis(database.getCAxisList().get(labels[0]));
    barChartControl = new C_BarView(barChartView, controlManager, cTooltip);
    
    // CREATE THE TREE MAP
    treeView = new TreeMapView(pad, pad*2, gridSize+180, gridSize + 250, controlManager, this);
    //changed the label numbers in this while updating which columns are parsed, not sure which numbers they're supposed to be.
    treeView.makeTree(database.getCAxisList().get(labels[11]), database.getCAxisList().get(labels[10]), database.getCAxisList().get(labels[9]));
    treeMapControl = new C_TreeMap(treeView, controlManager, cTooltip);
    
    //globalUIElements = new MappingManager(controlManager, viewManager, 200, 0, this);
    generatedGradient = generateGradient(gradientColors[0], gradientColors[1], 1, 256);
    
    deselectButton = new TextButton(null, controlManager, "deselect", 50, 12, this);
    deselectButton.addSubscriber(this);
    
    // set up communication between the bar view controller and the tree view controller:
    barChartControl.addSubscriber(treeMapControl);
    treeMapControl.addSubscriber(barChartControl);
    
    reDraw(); // update the view once
  }

  // TODO: what we want is to manage when to call draw() rather than it being called every frame.
  // Controllers will be handling that.
  @Override
  public void draw()
  {
	super.draw(); // super.draw() will update the control manager	
	reDraw();
  }
  
  @Override
  public void reDraw()
  {
	background( backgroundColor );
	// draw all our charts:
	barChartView.display(this);
	treeView.display(this);
	    
    // draw UI options:
    textFont(header);
    strokeWeight(0);
    fill(0);
    text("Lots Of Planning", 20, 15);
    textFont(body);
    text("an info viz tool for city planners", 20, 30);
    
    // draw other components:
    viewManager.displayUI();
    // TODO: fix the tooltip so it actually works
    vTooltip.display(this);
  }
  
  // use this method to get our new list of categorical axis from the "database":
  public HashMap<String, ScatterPlotCAxis> getCAxisList()
  {
	  return database.getCAxisList();
  }

  // ----------------------
  // UI and Input Stuff:
  // ----------------------
  /*void handleEvent(String trigger, EventOwner obj)
  {
    println(trigger);
    if(trigger.equals("Close All Windows"))
    {
      controlManager.rightClickEvent();
    }
    else if(trigger.equals("Deselect All"))
    {
      controlManager.rightClickEvent();
    }
  }*/

  /* *
   * OVERRIDE PROCESSING EVENTS
   * when mouse is clicked, forward this information to the controlManager
   * special care is taken to differentiate between single and double clicking
   * */
  public void mouseClicked()
  {
    if(mouseButton == LEFT){
      controlManager.updateControllers(mouseX, mouseY, "leftClick");
      /*for(int i = 0; i < charts.length; i++)
      {
        charts[i].onInteract(mouseX, mouseY, "leftClick");
      }*/
    }
    else{
      controlManager.updateControllers(mouseX, mouseY, "rightClick");
      /*for(int i = 0; i < charts.length; i++)
      {
        charts[i].onInteract(mouseX, mouseY, "rightClick");
      }*/
    }
  }
  public void mouseDragged()
  {
    if(mouseButton == LEFT){
      controlManager.updateControllers(mouseX, mouseY, "leftDrag");
    }
  }
  public void mouseReleased()
  {
      controlManager.updateControllers(mouseX, mouseY, "released");
  }

  public void keyPressed(){}
  public void keyReleased(){}

  // set the element at index i to be selected
  public void selectAnElement(int index)
  {
	  parrallelCoordinateView.selectLine(index);
  }
  
  public void deselectElement()
  {
	  parrallelCoordinateView.deselectCurrentLine();  
  }

  // this gradient is generated in setup and used to represent a range of float values when mapped to color:
  public int[] generateGradient(int top, int bottom, int w, int h) 
  {
    int tR = (top >> 16) & 0xFF;
    int tG = (top >> 8) & 0xFF;
    int tB = top & 0xFF;
    int bR = (bottom >> 16) & 0xFF;
    int bG = (bottom >> 8) & 0xFF;
    int bB = bottom & 0xFF;

    int[] gradientPixels = new int[w*h];
     
    //bg = createImage(w,h,RGB);
    //bg.loadPixels();
    for(int i=0; i < w*h; i++) {
      int y = i/w;
      float n = y/(float)h;
      // for a horizontal gradient:
      // float n = x/(float)bg.width;
      gradientPixels[i] = color(
      lerp(tR,bR,n), 
      lerp(tG,bG,n), 
      lerp(tB,bB,n), 
      255); 
    }
    return gradientPixels;
  }
  
  public int[] getGradient()
  {
	  return generatedGradient;
  }
  
  public HashMap[] getAxisList()
  {
	  //return axisList;
	  return null;
  }
  
  public DisplayList getViewManager() {
	  return viewManager;
  }
  
  public ControlManager getControlManager() {
	  return controlManager;
  }

  @Override
  public void handleEvent(String trigger, EventOwner obj) {
	  if(trigger.equals("buttonPressed"))
	  {
		  deselectElement();
		  for(int i = 0; i < charts.length; i++)
	      {
	        charts[i].deselectPoint();
	      }
	  }	
  }

	public C_TooltipControl getTooltipController() {
		return cTooltip;
	}
}